float4x4 World;
float4x4 View;
float4x4 Proj;
float4x4 InvView;
float4x4 InvViewProj;
float4x4 InvProj;
float4x4 ViewProjection;
float Time;

#define BASE_DIM_FLOAT 8.0f
#define INV_BASE_DIM (1.0f / BASE_DIM_FLOAT)


sampler sampleBaseData : register(s0);
sampler sampleMask : register(s2);

float2 BaseData2D(float x, float y)
{
	float permY = tex2D(sampleBaseData, float2(y, 0.5f + 0.5f * 0.5f)).x;
	return (tex2D(sampleBaseData, float2(x + permY, 0.0f + 0.5f * 0.5f)).xy - 0.5f) * 2.0f;
}

float3 BaseData3D(float x, float y, float z)
{
	float permZ = tex2D(sampleBaseData, float2(z, 0.5f + 0.5f * 0.5f)).x;
	float permY = tex2D(sampleBaseData, float2(y + permZ, 0.5f + 0.5f * 0.5f)).x;
	return (tex2D(sampleBaseData, float2(x + permY, 0.0f + 0.5f * 0.5f)).xyz - 0.5f) * 2.0f;
}

float2 GridDir2D(float x, float y, float2 texCoord)
{
	//Need to scale it up by the dimensions of a grid because the incoming coordinates
	//are between 0 and 1 / BASE_DIM_FLOAT. The result will be dotted with a vector of
	//unit length
	return float2(texCoord.x - x, texCoord.y - y) * BASE_DIM_FLOAT;
}

float3 GridDir3D(float x, float y, float z, float3 texCoord)
{
	//Need to scale it up by the dimensions of a grid because the incoming coordinates
	//are between 0 and 1 / BASE_DIM_FLOAT. The result will be dotted with a vector of
	//unit length
	return float3(texCoord.x - x, texCoord.y - y, texCoord.z - z) * BASE_DIM_FLOAT;
}

float Curve(float t)
{
	return (3 - 2 * t) * t * t;
}

float Noise2D(float2 uvCoord, float octave)
{
	uvCoord *= octave;
	float2 GridFrac = frac(uvCoord * BASE_DIM_FLOAT);
	
	float leftGrid = (floor(uvCoord.x * BASE_DIM_FLOAT)) / BASE_DIM_FLOAT;
	float rightGrid = leftGrid + (1.0f / BASE_DIM_FLOAT);
	float topGrid = (floor(uvCoord.y * BASE_DIM_FLOAT)) / BASE_DIM_FLOAT;
	float bottomGrid = topGrid + (1.0f / BASE_DIM_FLOAT);
	
	float tlDot = dot(BaseData2D(leftGrid, topGrid), GridDir2D(leftGrid, topGrid, uvCoord));
	float blDot = dot(BaseData2D(leftGrid, bottomGrid), GridDir2D(leftGrid, bottomGrid, uvCoord));
	float trDot = dot(BaseData2D(rightGrid, topGrid), GridDir2D(rightGrid, topGrid, uvCoord));
	float brDot = dot(BaseData2D(rightGrid, bottomGrid), GridDir2D(rightGrid, bottomGrid, uvCoord));
	
	float2 CurveWeights = float2(Curve(GridFrac.x),Curve(GridFrac.y));
	
	float final = lerp(
		lerp(tlDot, trDot, CurveWeights.x), 
		lerp(blDot, brDot, CurveWeights.x), 
		CurveWeights.y);
	
	final = (final + 0.5) / 2.0f;
	return final;
}

float Noise3D(float3 uvCoord, float octave)
{
	uvCoord *= octave;
	float3 GridFrac = frac(uvCoord * BASE_DIM_FLOAT);
	
	float leftGrid = (floor(uvCoord.x * BASE_DIM_FLOAT)) / BASE_DIM_FLOAT;
	float rightGrid = leftGrid + (1.0f / BASE_DIM_FLOAT);
	float topGrid = (floor(uvCoord.y * BASE_DIM_FLOAT)) / BASE_DIM_FLOAT;
	float bottomGrid = topGrid + (1.0f / BASE_DIM_FLOAT);
	float frontGrid = (floor(uvCoord.z * BASE_DIM_FLOAT)) / BASE_DIM_FLOAT;
	float backGrid = frontGrid + (1.0f / BASE_DIM_FLOAT);
	
	float ftlDot = dot(BaseData3D(leftGrid, topGrid, frontGrid), GridDir3D(leftGrid, topGrid, frontGrid, uvCoord));
	float fblDot = dot(BaseData3D(leftGrid, bottomGrid,frontGrid), GridDir3D(leftGrid, bottomGrid, frontGrid,uvCoord));
	float ftrDot = dot(BaseData3D(rightGrid, topGrid,frontGrid), GridDir3D(rightGrid, topGrid, frontGrid,uvCoord));
	float fbrDot = dot(BaseData3D(rightGrid, bottomGrid,frontGrid), GridDir3D(rightGrid, bottomGrid, frontGrid,uvCoord));
	float btlDot = dot(BaseData3D(leftGrid, topGrid,backGrid), GridDir3D(leftGrid, topGrid,backGrid, uvCoord));
	float bblDot = dot(BaseData3D(leftGrid, bottomGrid,backGrid), GridDir3D(leftGrid, bottomGrid, backGrid,uvCoord));
	float btrDot = dot(BaseData3D(rightGrid, topGrid,backGrid), GridDir3D(rightGrid, topGrid, backGrid,uvCoord));
	float bbrDot = dot(BaseData3D(rightGrid, bottomGrid,backGrid), GridDir3D(rightGrid, bottomGrid, backGrid,uvCoord));
	
	float3 CurveWeights = float3(Curve(GridFrac.x),Curve(GridFrac.y),Curve(GridFrac.z));
	
	float final = 
	lerp(
	lerp(	lerp(ftlDot, ftrDot, CurveWeights.x),
			lerp(btlDot, btrDot, CurveWeights.x),
			CurveWeights.z ),
	lerp(	lerp(fblDot, fbrDot, CurveWeights.x),
			lerp(bblDot, bbrDot, CurveWeights.x),
			CurveWeights.z ),
			CurveWeights.y);
	
	//Less structure	
	final = clamp(final * 10, -1, 1);
	
	//More structure
	//final = clamp(final * 30, -1, 1);
	
	final = (final + 0.5) / 2.0f;
	return final;
}

void PixelShaderFunction(	uniform float inOctave,
							float4 inPosition : POSITION0,
							float4 inTexCoord : TEXCOORD0,
							float3 inColor : COLOR,
							out float4 outColor : COLOR0)
{
	outColor.xyz = inColor;
	
	//More structure
	float a = 1.0f;
	//Less structure
	//float a = 0.5f;
	
	//outColor = tex2D(sampleBaseData, inTexCoord.xy);
	outColor.w = Noise3D(inTexCoord.xyz,inOctave) * a;
}


void VertexShaderFunction(float4 inPosition : POSITION0,
							float2 inTexCoord : TEXCOORD0,
							float3 inNormal : NORMAL0,
							out float4 outPosition : POSITION0,
							out float4 outTexCoord : TEXCOORD0,
							out float3 outColor : COLOR
)
{
	const float NOISE_DEPTH_SCALE = 5.0f;
	outTexCoord = (float4)0.0f;
	
    
    outPosition.z = inPosition.z * NOISE_DEPTH_SCALE;
    outPosition.w = 1;
    outPosition.xy = inTexCoord * 2 - 1;
    
    float4 tCoord = outPosition;
    tCoord.xy *= 0.4;
    
    outTexCoord.xyz = mul(tCoord,InvViewProj).xyz;
    
	outColor = 1- inPosition.z;
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader = compile ps_3_0 PixelShaderFunction(1.0f);
    }
    
    /*
    pass Pass2
    {
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader = compile ps_3_0 PixelShaderFunction(2.0f);
    }
    
    pass Pass3
    {
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader = compile ps_3_0 PixelShaderFunction(4.0f);
    }
    
    pass Pass4
    {
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader = compile ps_3_0 PixelShaderFunction(8.0f);
    }
    */
}
